| 特性 | 说明 |
|---|---|
| 不可变性 | 创建后内容不能增加、删除或修改 |
| 有序性 | 元素按插入顺序存储,可通过索引访问 |
| 异构性 | 可包含不同类型的元素(整数、字符串等) |
| 轻量性 | 比列表更节省内存空间 |
| 可迭代性 | 可用于for循环、推导式等 |
# 方式1: 使用圆括号创建元组
# 圆括号是可选的,但加上可以提高代码可读性
tup1 = ('physics', 'chemistry', 1997, 2000) # 包含字符串和整数的混合元组
tup2 = (1, 2, 3, 4, 5) # 纯整数元组
tup3 = "a", "b", "c", "d" # 不加括号也可以,Python会自动识别为元组
# 创建空元组
# 空元组常用于初始化变量或作为函数默认参数
empty_tup = ()
# 创建单元素元组(注意逗号!)
# 这是一个常见的陷阱:单个元素后面必须有逗号,否则会被识别为带括号的表达式
single_tup = (50,) # 正确:有逗号,是元组
not_a_tuple = (50) # 错误:没有逗号,这只是整数50
# 打印结果以验证类型
print('元组1:', tup1)
print('元组2:', tup2)
print('元组3:', tup3) # 证明不加括号也能创建元组
print('空元组:', empty_tup)
print('单元素元组:', single_tup)元组1: ('physics', 'chemistry', 1997, 2000)
元组2: (1, 2, 3, 4, 5)
元组3: ('a', 'b', 'c', 'd')
空元组: ()
单元素元组: (50,)
(50,) → 这是一个元组(有逗号)(50) → 这只是整数50(没有逗号)从列表: (1, 2, 3, 4)
从字符串: ('H', 'e', 'l', 'l', 'o')
从range: (0, 1, 2, 3, 4)
| 场景 | 推荐方法 | 理由 |
|---|---|---|
| 已知元素,数量少 | tup = (1, 2) |
简洁直观 |
| 从其他序列转换 | tuple(seq) |
清晰表达意图 |
| 需要计算生成元素 | tuple(x for x in ...) |
内存高效 |
| 需要空元组 | empty = () |
最简洁 |
# 创建示例元组
tup1 = ('physics', 'chemistry', 1997, 2000) # 混合类型元组
tup2 = (1, 2, 3, 4, 5, 6, 7) # 纯数字元组
# 正向索引:从0开始,从左向右数
print('tup1[0]:', tup1[0]) # 第一个元素:'physics'
print('tup1[1]:', tup1[1]) # 第二个元素:'chemistry'
# 负向索引:从-1开始,从右向左数
print('tup2[-1]:', tup2[-1]) # 最后一个元素:7
print('tup2[-2]:', tup2[-2]) # 倒数第二个元素:6
# 切片操作:获取子元组
# 语法:tup[start:end:step]
# start包含,end不包含(左闭右开区间)
print('tup2[1:5]:', tup2[1:5]) # 索引1到4的元素:(2, 3, 4, 5)
print('tup2[::2]:', tup2[::2]) # 每隔一个取一个:(1, 3, 5, 7)
print('tup2[::-1]:', tup2[::-1]) # 反转元组:(7, 6, 5, 4, 3, 2, 1)tup1[0]: physics
tup1[1]: chemistry
tup2[-1]: 7
tup2[-2]: 6
tup2[1:5]: (2, 3, 4, 5)
tup2[::2]: (1, 3, 5, 7)
tup2[::-1]: (7, 6, 5, 4, 3, 2, 1)
| 语法 | 含义 | 示例 |
|---|---|---|
[start:end] |
从start到end-1 | tup[1:5] |
[start:end:step] |
按步长取元素 | tup[::2] |
[:end] |
从头开始 | tup[:3] |
[start:] |
到结尾 | tup[2:] |
[::-1] |
反转序列 | tup[::-1] |
IndexErrortry/except 或先检查 len() 来避免# 创建一个元组
tup = (12, 34.56)
# 尝试修改元组的第一个元素
try:
tup[0] = 20 # 这会抛出TypeError
except TypeError as e:
print(f'错误类型: {type(e).__name__}')
print(f'错误信息: {e}')
print('结论:元组元素一旦创建就不能修改')
# 虽然不能修改,但可以连接两个元组创建新元组
# 注意:这不是修改原元组,而是创建了一个全新的元组
tup3 = tup + ('abc', 'xyz')
print('原元组:', tup) # 原元组保持不变
print('新元组:', tup3) # 这是一个新创建的元组
# 也可以通过重复创建新元组
tup4 = tup * 2 # 元组重复
print('重复元组:', tup4)错误类型: TypeError
错误信息: 'tuple' object does not support item assignment
结论:元组元素一旦创建就不能修改
原元组: (12, 34.56)
新元组: (12, 34.56, 'abc', 'xyz')
重复元组: (12, 34.56, 12, 34.56)
| 理由 | 说明 |
|---|---|
| 数据安全性 | 历史交易记录一旦生成就不应被修改 |
| 多线程环境 | 不可变对象是线程安全的,无需加锁 |
| 哈希要求 | 只有不可变对象才能作为字典键 |
| 函数式编程 | 使程序更易于推理和测试 |
| 内存优化 | Python可对相同内容的元组共享内存 |
# 定义交易策略的核心参数
# 使用元组确保这些参数不会被意外修改
trading_params = (
100000, # 初始资金(元)
0.05, # 预期年收益率
30, # 投资期限(年)
0.6 # 股票配置比例
)
# 元组解包:将元组的元素分别赋值给变量
# 这种写法比分别访问元组元素更清晰
initial_capital, rate, years, stock_ratio = trading_params
# 格式化输出参数
# 使用f-string进行格式化,提高可读性
print(f'初始资金: {initial_capital:,.0f}元') # 添加千位分隔符
print(f'年利率: {rate:.1%}') # 百分比格式
print(f'投资期限: {years}年')
print(f'股票配置: {stock_ratio:.0%}')
# 计算期末资产
final_amount = initial_capital * (1 + rate) ** years
print(f'期末资产(复利): {final_amount:,.2f}元')初始资金: 100,000元
年利率: 5.0%
投资期限: 30年
股票配置: 60%
期末资产(复利): 432,194.24元
# 创建价格查找表
# 键是(股票代码, 日期)的元组,值是收盘价
price_lookup = {
('600519.SH', '2024-01-15'): 1856.00,
('600519.SH', '2024-01-16'): 1862.50,
('000858.SZ', '2024-01-15'): 158.20,
('000858.SZ', '2024-01-16'): 159.80
}
# 查询特定股票在特定日期的价格
stock = '600519.SH'
date = '2024-01-15'
price = price_lookup.get((stock, date))
if price:
print(f'{stock} 在 {date} 的收盘价是 {price:.2f}元')
else:
print('未找到匹配的价格数据')
# 只有不可变对象(如元组)才能作为字典键
# 下面的代码会报错,因为列表是可变的:
# error_dict = {['600519.SH', '2024-01-15']: 1856.00} # TypeError600519.SH 在 2024-01-15 的收盘价是 1856.00元
def calculate_return_metrics(prices):
'''
计算价格序列的多个收益率指标
参数:
prices: 价格列表
返回:
(总收益率, 年化收益率, 波动率)的元组
'''
import numpy as np
# 计算简单收益率
returns = np.diff(prices) / prices[:-1]
# 总收益率
total_return = (prices[-1] - prices[0]) / prices[0]
# 年化收益率(假设252个交易日)
annual_return = (1 + total_return) ** (252 / len(prices)) - 1
# 年化波动率
annual_volatility = returns.std() * np.sqrt(252)
return total_return, annual_return, annual_volatility
# 使用示例
stock_prices = [100, 102, 101, 105, 108, 107, 110]
total_ret, ann_ret, ann_vol = calculate_return_metrics(stock_prices)
print(f'总收益率: {total_ret:.2%}')
print(f'年化收益率: {ann_ret:.2%}')
print(f'年化波动率: {ann_vol:.2%}')总收益率: 10.00%
年化收益率: 2991.27%
年化波动率: 30.26%
# 定义一个时间戳数据点
tick = ('600519.SH', '2024-01-15 09:30:00', 1856.00, 100)
# 格式:(股票代码, 时间戳, 价格, 成交量)
# 元组解包提取字段
symbol, timestamp, price, volume = tick
print(f'股票代码: {symbol}')
print(f'时间戳: {timestamp}')
print(f'价格: {price:.2f}元')
print(f'成交量: {volume}手')
# 将多个tick数据组成列表
ticks = [
('600519.SH', '09:30:00', 1856.00, 100),
('600519.SH', '09:31:00', 1858.50, 150),
('600519.SH', '09:32:00', 1855.00, 80),
]
# 分析第一分钟的价格变化
price_change = ticks[1][2] - ticks[0][2]
print(f'第一分钟价格变化: {price_change:+.2f}元')股票代码: 600519.SH
时间戳: 2024-01-15 09:30:00
价格: 1856.00元
成交量: 100手
第一分钟价格变化: +2.50元
| 选择元组 | 选择列表 |
|---|---|
| 数据需要保护、不应修改 | 数据会频繁增删 |
| 需要用作字典键 | 逐步构建数据序列 |
| 性能敏感,大量小对象 | 需要临时存储中间结果 |
| 函数返回多个值 | 需要排序、追加等操作 |
| 固定的记录结构 | 动态变化的集合 |
import sys
import timeit
# 创建相同内容的元组和列表
tup = tuple(range(1000))
lst = list(range(1000))
# 内存占用比较
print(f'元组内存占用: {sys.getsizeof(tup)} 字节')
print(f'列表内存占用: {sys.getsizeof(lst)} 字节')
print(f'元组更节省: {sys.getsizeof(lst) - sys.getsizeof(tup)} 字节')
# 访问速度比较
tup_time = timeit.timeit('x = tup[500]', globals=globals(), number=1000000)
lst_time = timeit.timeit('x = lst[500]', globals=globals(), number=1000000)
print(f'元组访问时间: {tup_time:.4f}秒')
print(f'列表访问时间: {lst_time:.4f}秒')
print(f'元组速度提升: {(lst_time/tup_time - 1)*100:.1f}%')元组内存占用: 8040 字节
列表内存占用: 8056 字节
元组更节省: 16 字节
元组访问时间: 0.0270秒
列表访问时间: 0.0249秒
元组速度提升: -7.8%
from collections import namedtuple
# 定义一个命名元组类型
# 相当于创建了一个简单的类
Stock = namedtuple('Stock', ['symbol', 'price', 'volume'])
# 创建Stock实例
stock1 = Stock('600519.SH', 1856.00, 1000)
stock2 = Stock(symbol='000858.SZ', price=158.20, volume=5000)
# 可以像元组一样索引访问
print(f'股票代码(索引): {stock1[0]}')
# 也可以像对象一样属性访问
print(f'股票代码(属性): {stock1.symbol}')
print(f'价格: {stock1.price}')
print(f'成交量: {stock1.volume}')
# 命名元组仍然是元组,是不可变的
print(f'是否为元组: {isinstance(stock1, tuple)}')
# 命名元组有友好的字符串表示
print(f'股票信息: {stock1}')股票代码(索引): 600519.SH
股票代码(属性): 600519.SH
价格: 1856.0
成交量: 1000
是否为元组: True
股票信息: Stock(symbol='600519.SH', price=1856.0, volume=1000)
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
name = "中国通号" # 设置名称为"中国通号"
print('name:',type(name)) # 输出name
code = "688009" # 设置代码为"688009"
print('code:',type(code)) # 输出code
IPO_date = "2019年7月22日" # 设置日期为"2019年7月22日"
print('IPO_data:',type(IPO_date)) # 输出IPO_data
exchange = "上海证券交易所" #以字符串输入中国通号A股的上市交易所
print('exchange',type(exchange)) #使用type函数输出数据类型
capital = 10589819000 # 总股本:10589819000股
print('capital',type(capital)) # 输出capital
shares = 8621018000 # 流通股本:8621018000股
print('share:',type(shares)) # 输出share
price_IPO = 5.85 #以浮点型输入中国通号A股发行价
print('price_IPO:',type(price_IPO)) #使用type函数输出数据类型并使用print函数打印
price_Jul22 = 12.27 # 设置当前价格为12.27
print('price_Jul22:',type(price_Jul22)) # 输出price_Jul22
change_Jul22 = 1.09744 # 涨幅:109.744%
print('change_Jul22:',type(change_Jul22)) # 输出change_Jul22name: <class 'str'>
code: <class 'str'>
IPO_data: <class 'str'>
exchange <class 'str'>
capital <class 'int'>
share: <class 'int'>
price_IPO: <class 'float'>
price_Jul22: <class 'float'>
change_Jul22: <class 'float'>
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
name = "中国通号" # 设置名称为"中国通号"
code = "688009" # 设置代码为"688009"
IPO_date = "2019年7月22日" # 设置日期为"2019年7月22日"
exchange = "上海证券交易所" # 设置交易所为"上海证券交易所"
capital = 10589819000 # 总股本:10589819000股
shares = 8621018000 # 流通股本:8621018000股
price_IPO = 5.85 # 设置当前价格为5.85
price_Jul22 = 12.27 # 设置当前价格为12.27
change_Jul22 = 1.09744 # 涨幅:109.744%
tup =(name,code,IPO_date,exchange,capital,shares,price_IPO,price_Jul22,change_Jul22) #创建一个元组,包括以上数据
print(tup) #打印输出这个元组
print(tup[0]) #访问该元组的首个元素
print(tup[-1]) #访问该元组的末尾元素
print(tup[2:6])#访问该元组的第3个至第6个元素('中国通号', '688009', '2019年7月22日', '上海证券交易所', 10589819000, 8621018000, 5.85, 12.27, 1.09744)
中国通号
1.09744
('2019年7月22日', '上海证券交易所', 10589819000, 8621018000)
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
name = "中国通号" # 设置名称为"中国通号"
code = "688009" # 设置代码为"688009"
IPO_date = "2019年7月22日" # 设置日期为"2019年7月22日"
exchange = "上海证券交易所" # 设置交易所为"上海证券交易所"
capital = 10589819000 # 总股本:10589819000股
shares = 8621018000 # 流通股本:8621018000股
price_IPO = 5.85 # 设置当前价格为5.85
price_Jul22 = 12.27 # 设置当前价格为12.27
change_Jul22 = 1.09744 # 涨幅:109.744%
tup = (name,code,IPO_date,exchange,capital,shares,price_IPO,price_Jul22,change_Jul22) # 定义元组tup
price_Jul22_H = 5.43 #以浮点型输入中国通号H股7月22日收盘价
change_Jul22_H = -0.1171 #以浮点数输入中国通号H股7月22日涨跌幅
del tup #删除任务2中创建的元组
tup_new = (name,code,IPO_date,exchange,capital,shares,price_IPO,price_Jul22,change_Jul22,price_Jul22_H,change_Jul22_H) #创建包含H股股价和涨跌幅的新元组
print(tup_new) #打印这个新元组('中国通号', '688009', '2019年7月22日', '上海证券交易所', 10589819000, 8621018000, 5.85, 12.27, 1.09744, 5.43, -0.1171)
[商业大数据分析与应用]